from common.instruction import *
from common.tableprint import tprint
from .taskmanager import TaskManager

class Controller(object):
    """
    后台服务的核心控制类，整个服务的运行逻辑
     主要的功能是：全局状态感知（数据获取与加工）及控制服务（路径规划、任务调度）

    与其他模块的调用关系如下：

     +--------------------------------------------+
     | 任务调度 | 路径规划 | websocket |  web服务   |
     +--------------------------------------------+
         ↑↓                    ↑↓           ↑↓     
     +--------------------------------------------+
     |                Controller                  |
     +--------------------------------------------+
                          ↑↓                
     +--------------------------------------------+
     |              （虚拟）上位机                 |
     +--------------------------------------------+
    """

    def __init__(self, config=None):
        # 记录当前时间
        self.__now = 0
        # 保存上位机发来的小车状态，一个 dict 的数组
        self.__aivs = []
        # 初始化任务管理器
        self.task_manager = TaskManager()
        # 绑定事件处理器
        self.__bind_event_hanlders()
        
    def register_components(self, dispatcher):
        """
        注册要使用的组件（组件需要在外部初始化好）。
        这里是指车辆调度模块
        """
        self.dispatcher = dispatcher

    def setup_upper(self, upper):
        """
        挂载虚拟上位机（码头）
        """
        self.upper = upper
        self.upper.emit_event = self.event_happend
    
    @property
    def now_time(self) -> int:
        """
        获取当前时间
        """
        return round(self.__now, 1)
    
    def update_time(self, now):
        """
        由上位机更新这里的时间
        """
        self.__now = now

    @property
    def aivs_info(self):
        """
        返回场景中的所有 aiv 信息
        """
        return self.__aivs

    def update_aivs(self, aivs):
        """
        有上位机实时将 aiv 的最新状态推过来
        """
        self.__aivs = aivs
        self.dispatcher.traffic_arrangement(aivs)

    @property
    def tasks(self) -> list:
        """
        当前所有的任务对象
        """
        return self.task_manager.tasks

    @property
    def tasks_info(self) -> list:
        """
        当前所有的任务信息
        """
        return self.task_manager.tasks_info
    
    @property
    def tasks_waiting(self) -> list:
        """
        获取任务列表中还未执行的任务
        """
        return self.task_manager.tasks_waiting

    def add_tasks(self, tasks: list) -> list:
        """
        一次性添加多个任务，添加完毕后调度一次。
         返回值为成功添加的任务id
        """
        ids = self.task_manager.add_tasks(tasks, self.now_time)
        self.distribute_tasks()
        return ids

    def distribute_tasks(self):
        """
        对当前已经接收到的任务执行调度
        """
        tasks_waiting = self.task_manager.tasks_waiting
        
        # 获取调度结果
        instructions = self.dispatcher.arrange_for_tasks(tasks_waiting, self.__aivs, self.__now)
        
        # 更新到虚拟场景中
        self.upper.dispatch(instructions)
        
        tprint(list(map(lambda ins: ins.info, instructions)))

    def arrange_one_aiv(self, aiv, signal=None):
        """
        单车调度，输入
        - aiv（必须）卡车状态信息
        - signal（可无）卡车想干嘛。

        如果 signal 为空或者不传，意味着多出一辆自由车，可能会改变目前的最优任务分配。
        - 如果任务的最优分配被改变，则会返回一组 Instruction []，为场地中的 aiv 重新分发任务
        - 如果多出的这辆车不影响任务分配，则会返回一条 Instruction，将该车调度到休息区（或者充电区）
        """
        
        # 如果没有明确的目的地信号
        if not signal:
            # 首先检查自由车是否影响当前任务的最优分配
            # -----

            # 不会产生更优的任务分配，去休息区 
            # KTODO 提前去充电区
            # KTODO 字符串 'rest' 换成一个全局变量？
            signal = 'rest'

        # 有明确的信号，直接调度到信号对应的目的地
        ins = self.dispatcher.arrange_for_aiv(aiv, signal)
        self.upper.dispatch(ins)
        return ins

    def receive_signal(self, params):
        """
        上位机发过来的信号
        """
        aiv = params.get('aiv')
        signal = params.get('signal', None)
        print('[signal]', signal)
        
        self.arrange_one_aiv(aiv, signal)

    def event_happend(self, event, params):
        """
        场景中有事件发生时
        """
        handler = self.event_handlers.get(event, None)
        
        if not handler:
            return
        
        if not event.startswith('update'):
            print('[event] %s' % event)

        handler(params)

    def __bind_event_hanlders(self):
        """
        以传统字典方式实现 switch-case 语法
        """
        self.event_handlers = {
            'update-time': self.update_time,
            'update-aivs': self.update_aivs,
            'add-tasks': self.add_tasks,
            'task-finished': self.receive_signal
        }